Micron Document
🎖️GitЯра🎖️


Displaying Raw • Download

core/network/src/jvmMain/kotlin/org/meshtastic/core/network/SerialTransport.kt bd2863243bab6eb213401d949839a2bc74dde7e2 (bd286324) Text, 19.08 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.network

Tff7b72import T7ee787co.touchlab.kermit.Logger
Tff7b72import T7ee787com.fazecast.jSerialComm.SerialPort
Tff7b72import T7ee787com.fazecast.jSerialComm.SerialPortTimeoutException
Tff7b72import T7ee787kotlinx.atomicfu.locks.SynchronizedObject
Tff7b72import T7ee787kotlinx.atomicfu.locks.synchronized
Tff7b72import T7ee787kotlinx.coroutines.CancellationException
Tff7b72import T7ee787kotlinx.coroutines.CoroutineScope
Tff7b72import T7ee787kotlinx.coroutines.CoroutineStart
Tff7b72import T7ee787kotlinx.coroutines.Job
Tff7b72import T7ee787kotlinx.coroutines.NonCancellable
Tff7b72import T7ee787kotlinx.coroutines.cancelAndJoin
Tff7b72import T7ee787kotlinx.coroutines.currentCoroutineContext
Tff7b72import T7ee787kotlinx.coroutines.isActive
Tff7b72import T7ee787kotlinx.coroutines.launch
Tff7b72import T7ee787kotlinx.coroutines.runInterruptible
Tff7b72import T7ee787kotlinx.coroutines.withContext
Tff7b72import T7ee787kotlinx.coroutines.withTimeoutOrNull
Tff7b72import T7ee787org.meshtastic.core.common.util.handledLaunch
Tff7b72import T7ee787org.meshtastic.core.di.CoroutineDispatchers
Tff7b72import T7ee787org.meshtastic.core.network.radio.StreamTransport
Tff7b72import T7ee787org.meshtastic.core.network.radio.TransportLifecycleGate
Tff7b72import T7ee787org.meshtastic.core.network.transport.HeartbeatSender
Tff7b72import T7ee787org.meshtastic.core.network.transport.StreamFrameCodec
Tff7b72import T7ee787org.meshtastic.core.repository.RadioTransportCallback
Tff7b72import T7ee787java.io.File
Tff7b72import T7ee787java.io.IOException
Tff7b72import T7ee787java.util.concurrent.TimeUnit
Tff7b72import T7ee787kotlin.time.Duration.Companion.seconds

Tff7b72private Tff7b72const Tff7b72val Te6edf3SERIAL_WRITE_RETRY_DELAY_MS Tff7b72= T79c0ff1T79c0ff0L
Tff7b72private Tff7b72const Tff7b72val Te6edf3NANOS_PER_MILLISECOND Tff7b72= T79c0ff1Te6edf3_000_000L
Tff7b72private Tff7b72const Tff7b72val Te6edf3SERIAL_DATA_BITS Tff7b72= T79c0ff8
Tff7b72private Tff7b72const Tff7b72val Te6edf3SERIAL_READ_TIMEOUT_MS Tff7b72= T79c0ff1T79c0ff0T79c0ff0
Tff7b72private Tff7b72const Tff7b72val Te6edf3SERIAL_READ_BUFFER_SIZE Tff7b72= T79c0ff1T79c0ff0T79c0ff2T79c0ff4
Tff7b72private Tff7b72const Tff7b72val Te6edf3SERIAL_WRITE_TIMEOUT_MS Tff7b72= T79c0ff5Te6edf3_000
Tff7b72private Tff7b72const Tff7b72val Te6edf3SERIAL_GROUP_LOOKUP_TIMEOUT_MS Tff7b72= T79c0ff2Te6edf3_000L
Tff7b72private Tff7b72val Te6edf3SERIAL_START_JOIN_TIMEOUT Tff7b72= T79c0ff1T79c0ff0.Te6edf3seconds

Tff7b72private Tff7b72val Te6edf3IS_WINDOWS_HOST Tff7b72= Te6edf3SystemTb4b4b4.Te6edf3getPropertyTb4b4b4(Ta5d6ff"Ta5d6ffos.nameTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3lowercaseTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff"Ta5d6ffwindowsTa5d6ff"Tb4b4b4)

Tff7b72private Tff7b72class T56d364SerialPortState Tb4b4b4{
Tff7b72private Tff7b72val Te6edf3lock Tff7b72= Te6edf3SynchronizedObjectTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72var Te6edf3portTb4b4b4: Te6edf3SerialPort? Tff7b72= Tff7b72null
Tff7b72private Tff7b72var Te6edf3startJobTb4b4b4: Te6edf3Job? Tff7b72= Tff7b72null
Tff7b72private Tff7b72var Te6edf3readJobTb4b4b4: Te6edf3Job? Tff7b72= Tff7b72null
Tff7b72private Tff7b72var Te6edf3closing Tff7b72= Tff7b72false

Tff7b72fun Td2a8ffpublishStartJobTb4b4b4(Te6edf3jobTb4b4b4: Te6edf3JobTb4b4b4, Te6edf3lifecycleClosedTb4b4b4: Tffa657BooleanTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Te6edf3synchronizedTb4b4b4(Te6edf3lockTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3unavailable Tff7b72= Te6edf3closing Tff7b72|Tff7b72| Te6edf3lifecycleClosed Tff7b72|Tff7b72| Te6edf3startJobTff7b72?.Te6edf3isCompleted Tff7b72=Tff7b72= Tff7b72false Tff7b72|Tff7b72| Te6edf3portTff7b72?.Te6edf3isOpen Tff7b72=Tff7b72= Tff7b72true
Tff7b72if Tb4b4b4(Te6edf3unavailableTb4b4b4) Tff7b72false Tff7b72else Tff7b72trueTb4b4b4.Te6edf3also Tb4b4b4{ Te6edf3startJob Tff7b72= Te6edf3job Tb4b4b4}
Tb4b4b4}

Tff7b72fun Td2a8ffisClosingTb4b4b4(Te6edf3lifecycleClosedTb4b4b4: Tffa657BooleanTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Te6edf3synchronizedTb4b4b4(Te6edf3lockTb4b4b4) Tb4b4b4{ Te6edf3closing Tff7b72|Tff7b72| Te6edf3lifecycleClosed Tb4b4b4}

Tff7b72fun Td2a8ffpublishPortTb4b4b4(Te6edf3candidateTb4b4b4: Te6edf3SerialPortTb4b4b4, Te6edf3lifecycleClosedTb4b4b4: Tffa657BooleanTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Te6edf3synchronizedTb4b4b4(Te6edf3lockTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3unavailable Tff7b72= Te6edf3closing Tff7b72|Tff7b72| Te6edf3lifecycleClosed Tff7b72|Tff7b72| Te6edf3port Tff7b72!Tff7b72= Tff7b72null
Tff7b72if Tb4b4b4(Te6edf3unavailableTb4b4b4) Tff7b72false Tff7b72else Tff7b72trueTb4b4b4.Te6edf3also Tb4b4b4{ Te6edf3port Tff7b72= Te6edf3candidate Tb4b4b4}
Tb4b4b4}

Tff7b72fun Td2a8ffcurrentOpenPortTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3SerialPort? Tff7b72= Te6edf3synchronizedTb4b4b4(Te6edf3lockTb4b4b4) Tb4b4b4{ Te6edf3portTff7b72?.Te6edf3takeIf Tb4b4b4{ Tff7b72!Te6edf3closing Tff7b72&Tff7b72& Tffa657itTb4b4b4.Te6edf3isOpen Tb4b4b4} Tb4b4b4}

Tff7b72fun Td2a8ffpublishReadJobTb4b4b4(Te6edf3expectedPortTb4b4b4: Te6edf3SerialPortTb4b4b4, Te6edf3jobTb4b4b4: Te6edf3JobTb4b4b4, Te6edf3lifecycleClosedTb4b4b4: Tffa657BooleanTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Te6edf3synchronizedTb4b4b4(Te6edf3lockTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3unavailable Tff7b72= Te6edf3closing Tff7b72|Tff7b72| Te6edf3lifecycleClosed Tff7b72|Tff7b72| Te6edf3port Tff7b72!Tff7b72=Tff7b72= Te6edf3expectedPort Tff7b72|Tff7b72| Te6edf3readJobTff7b72?.Te6edf3isActive Tff7b72=Tff7b72= Tff7b72true
Tff7b72if Tb4b4b4(Te6edf3unavailableTb4b4b4) Tff7b72false Tff7b72else Tff7b72trueTb4b4b4.Te6edf3also Tb4b4b4{ Te6edf3readJob Tff7b72= Te6edf3job Tb4b4b4}
Tb4b4b4}

Tff7b72fun Td2a8ffcanPublishTb4b4b4(Te6edf3expectedPortTb4b4b4: Te6edf3SerialPort?Tb4b4b4, Te6edf3requireNoPublishedPortTb4b4b4: Tffa657BooleanTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Te6edf3synchronizedTb4b4b4(Te6edf3lockTb4b4b4) Tb4b4b4{
Tff7b72!Te6edf3closing Tff7b72&Tff7b72& Tb4b4b4(Te6edf3expectedPort Tff7b72=Tff7b72= Tff7b72null Tff7b72|Tff7b72| Te6edf3port Tff7b72=Tff7b72=Tff7b72= Te6edf3expectedPortTb4b4b4) Tff7b72&Tff7b72& Tb4b4b4(Tff7b72!Te6edf3requireNoPublishedPort Tff7b72|Tff7b72| Te6edf3port Tff7b72=Tff7b72= Tff7b72nullTb4b4b4)
Tb4b4b4}

Tff7b72fun Td2a8ffretirePortTb4b4b4(Te6edf3expectedPortTb4b4b4: Te6edf3SerialPortTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72=
Te6edf3synchronizedTb4b4b4(Te6edf3lockTb4b4b4) Tb4b4b4{ Tb4b4b4(Te6edf3port Tff7b72=Tff7b72=Tff7b72= Te6edf3expectedPortTb4b4b4)Tb4b4b4.Te6edf3also Tb4b4b4{ Te6edf3owned Tff7b72-Tff7b72> Tff7b72if Tb4b4b4(Te6edf3ownedTb4b4b4) Te6edf3port Tff7b72= Tff7b72null Tb4b4b4} Tb4b4b4}

Tff7b72fun Td2a8ffbeginCloseTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3Job? Tff7b72= Te6edf3synchronizedTb4b4b4(Te6edf3lockTb4b4b4) Tb4b4b4{
Te6edf3closing Tff7b72= Tff7b72true
Te6edf3startJobTb4b4b4.Te6edf3also Tb4b4b4{ Te6edf3startJob Tff7b72= Tff7b72null Tb4b4b4}
Tb4b4b4}

Tff7b72fun Td2a8fftakeReadJobTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3Job? Tff7b72= Te6edf3synchronizedTb4b4b4(Te6edf3lockTb4b4b4) Tb4b4b4{ Te6edf3readJobTb4b4b4.Te6edf3also Tb4b4b4{ Te6edf3readJob Tff7b72= Tff7b72null Tb4b4b4} Tb4b4b4}

Tff7b72fun Td2a8fftakePortTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3SerialPort? Tff7b72= Te6edf3synchronizedTb4b4b4(Te6edf3lockTb4b4b4) Tb4b4b4{ Te6edf3portTb4b4b4.Te6edf3also Tb4b4b4{ Te6edf3port Tff7b72= Tff7b72null Tb4b4b4} Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffwriteFullyWithDeadlineTb4b4b4(Te6edf3portTb4b4b4: Te6edf3SerialPortTb4b4b4, Te6edf3payloadTb4b4b4: Te6edf3ByteArrayTb4b4b4, Te6edf3portNameTb4b4b4: Tffa657StringTb4b4b4, Te6edf3timeoutMsTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3startedNanos Tff7b72= Te6edf3SystemTb4b4b4.Te6edf3nanoTimeTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3timeoutNanos Tff7b72= Te6edf3timeoutMsTb4b4b4.Te6edf3toLongTb4b4b4(Tb4b4b4) Tff7b72* Te6edf3NANOS_PER_MILLISECOND
Tff7b72var Te6edf3offset Tff7b72= T79c0ff0
Tff7b72while Tb4b4b4(Te6edf3offset Tff7b72< Te6edf3payloadTb4b4b4.Te6edf3sizeTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3written Tff7b72= Te6edf3portTb4b4b4.Te6edf3writeBytesTb4b4b4(Te6edf3payloadTb4b4b4, Te6edf3payloadTb4b4b4.Te6edf3size Tff7b72- Te6edf3offsetTb4b4b4, Te6edf3offsetTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3written Tff7b72< T79c0ff0Tb4b4b4) Tb4b4b4{
Tff7b72throw Te6edf3IOExceptionTb4b4b4(Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3portNameTa5d6ff] Serial write failed after Tffd700$Te6edf3offsetTa5d6ff/Tffd700${Te6edf3payloadTb4b4b4.Te6edf3sizeTffd700}Ta5d6ff bytesTa5d6ff"Tb4b4b4)
Tb4b4b4}
Te6edf3offset Tff7b72+Tff7b72= Te6edf3written
Tff7b72if Tb4b4b4(Te6edf3offset Tff7b72< Te6edf3payloadTb4b4b4.Te6edf3sizeTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3SystemTb4b4b4.Te6edf3nanoTimeTb4b4b4(Tb4b4b4) Tff7b72- Te6edf3startedNanos Tff7b72>Tff7b72= Te6edf3timeoutNanosTb4b4b4) Tb4b4b4{
Tff7b72throw Te6edf3IOExceptionTb4b4b4(
Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3portNameTa5d6ff] Serial write timed out after Tffd700${Te6edf3timeoutMsTffd700}Ta5d6ffms at Tffd700$Te6edf3offsetTa5d6ff/Tffd700${Te6edf3payloadTb4b4b4.Te6edf3sizeTffd700}Ta5d6ff bytesTa5d6ff"Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
T8b949e// Partial writes can make progress while still keeping the driver continuously writable. Yield between
T8b949e// every retry so a slow device cannot turn this bounded loop into a CPU spin.
Te6edf3ThreadTb4b4b4.Te6edf3sleepTb4b4b4(Te6edf3SERIAL_WRITE_RETRY_DELAY_MSTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffconfigureSerialPortTb4b4b4(Te6edf3portTb4b4b4: Te6edf3SerialPortTb4b4b4, Te6edf3baudRateTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3portTb4b4b4.Te6edf3setComPortParametersTb4b4b4(Te6edf3baudRateTb4b4b4, Te6edf3SERIAL_DATA_BITSTb4b4b4, Te6edf3SerialPortTb4b4b4.Te6edf3ONE_STOP_BITTb4b4b4, Te6edf3SerialPortTb4b4b4.Te6edf3NO_PARITYTb4b4b4)
T8b949e// jSerialComm honors write timeouts only on Windows. TIMEOUT_NONBLOCKING is zero, so on other hosts the supplied
T8b949e// write-timeout argument is intentionally inert; writeFullyWithDeadline owns the cross-platform deadline instead.
Tff7b72val Te6edf3timeoutMode Tff7b72=
Te6edf3SerialPortTb4b4b4.Te6edf3TIMEOUT_READ_SEMI_BLOCKING Te6edf3or
Tff7b72if Tb4b4b4(Te6edf3IS_WINDOWS_HOSTTb4b4b4) Te6edf3SerialPortTb4b4b4.Te6edf3TIMEOUT_WRITE_BLOCKING Tff7b72else Te6edf3SerialPortTb4b4b4.Te6edf3TIMEOUT_NONBLOCKING
Te6edf3portTb4b4b4.Te6edf3setComPortTimeoutsTb4b4b4(Te6edf3timeoutModeTb4b4b4, Te6edf3SERIAL_READ_TIMEOUT_MSTb4b4b4, Te6edf3SERIAL_WRITE_TIMEOUT_MSTb4b4b4)
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffdiagnoseSerialOpenFailureTb4b4b4(Te6edf3portNameTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657String Tb4b4b4{
Tff7b72val Te6edf3osName Tff7b72= Te6edf3SystemTb4b4b4.Te6edf3getPropertyTb4b4b4(Ta5d6ff"Ta5d6ffos.nameTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)Tb4b4b4.Te6edf3lowercaseTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3devPath Tff7b72= Tff7b72if Tb4b4b4(Te6edf3portNameTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4)Tb4b4b4) Te6edf3portName Tff7b72else Ta5d6ff"Ta5d6ff/dev/Tffd700$Te6edf3portNameTa5d6ff"
Tff7b72val Te6edf3portFile Tff7b72= Te6edf3FileTb4b4b4(Te6edf3devPathTb4b4b4)
Tff7b72return Tff7b72when Tb4b4b4{
Tff7b72!Te6edf3osNameTb4b4b4.Te6edf3containsTb4b4b4(Ta5d6ff"Ta5d6fflinuxTa5d6ff"Tb4b4b4) Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffCould not open serial port: Tffd700$Te6edf3portNameTa5d6ff"

Tff7b72!Te6edf3portFileTb4b4b4.Te6edf3existsTb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffSerial port Tffd700$Te6edf3portNameTa5d6ff not found. Is the device still connected?Ta5d6ff"

Tff7b72!Te6edf3portFileTb4b4b4.Te6edf3canReadTb4b4b4(Tb4b4b4) Tff7b72|Tff7b72| Tff7b72!Te6edf3portFileTb4b4b4.Te6edf3canWriteTb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tb4b4b4{
Tff7b72val Te6edf3group Tff7b72= Te6edf3detectSerialGroupTb4b4b4(Te6edf3devPathTb4b4b4)
Ta5d6ff"Ta5d6ffPermission denied for Tffd700$Te6edf3devPathTa5d6ff. Add your account to the Tffd700$Te6edf3groupTa5d6ff group, then log out and back in.Ta5d6ff"
Tb4b4b4}

Tff7b72else Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffCould not open serial port: Tffd700$Te6edf3portNameTa5d6ff"
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffdetectSerialGroupTb4b4b4(Te6edf3devPathTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657String Tff7b72= Te6edf3runCatching Tb4b4b4{
Tff7b72val Te6edf3process Tff7b72= Te6edf3ProcessBuilderTb4b4b4(Ta5d6ff"Ta5d6ffstatTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff-cTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff%GTa5d6ff"Tb4b4b4, Te6edf3devPathTb4b4b4)Tb4b4b4.Te6edf3redirectErrorStreamTb4b4b4(Tff7b72trueTb4b4b4)Tb4b4b4.Te6edf3startTb4b4b4(Tb4b4b4)
Tff7b72try Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3processTb4b4b4.Te6edf3waitForTb4b4b4(Te6edf3SERIAL_GROUP_LOOKUP_TIMEOUT_MSTb4b4b4, Te6edf3TimeUnitTb4b4b4.Te6edf3MILLISECONDSTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffstat lookup for Tffd700$Te6edf3devPathTa5d6ff timed outTa5d6ff" Tb4b4b4}
Ta5d6ff"Ta5d6ffdialoutTa5d6ff"
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72val Te6edf3output Tff7b72= Te6edf3processTb4b4b4.Te6edf3inputStreamTb4b4b4.Te6edf3bufferedReaderTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3use Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3readTextTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4.Te6edf3trimTb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3processTb4b4b4.Te6edf3exitValueTb4b4b4(Tb4b4b4) Tff7b72!Tff7b72= T79c0ff0Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3detail Tff7b72= Te6edf3outputTb4b4b4.Te6edf3takeIfTb4b4b4(Tffa657StringTff7b72::Te6edf3isNotEmptyTb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{ Ta5d6ff"Ta5d6ff: Tffd700$Te6edf3itTa5d6ff" Tb4b4b4}Tb4b4b4.Te6edf3orEmptyTb4b4b4(Tb4b4b4)
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffstat lookup for Tffd700$Te6edf3devPathTa5d6ff failed with exit code Tffd700${Te6edf3processTb4b4b4.Te6edf3exitValueTb4b4b4(Tb4b4b4)Tffd700}Tffd700$Te6edf3detailTa5d6ff" Tb4b4b4}
Ta5d6ff"Ta5d6ffdialoutTa5d6ff"
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3outputTb4b4b4.Te6edf3takeIf Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72& Tffa657itTb4b4b4.Te6edf3noneTb4b4b4(Tffa657CharTff7b72::Te6edf3isWhitespaceTb4b4b4) Tb4b4b4} Tff7b72?: Ta5d6ff"Ta5d6ffdialoutTa5d6ff"
Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{
Te6edf3processTb4b4b4.Te6edf3destroyTb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3processTb4b4b4.Te6edf3isAliveTb4b4b4) Te6edf3processTb4b4b4.Te6edf3destroyForciblyTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4.Te6edf3getOrDefaultTb4b4b4(Ta5d6ff"Ta5d6ffdialoutTa5d6ff"Tb4b4b4)

Tff7b72private Tff7b72fun Td2a8ffcloseSerialPortTb4b4b4(Te6edf3portNameTb4b4b4: Tffa657StringTb4b4b4, Te6edf3portTb4b4b4: Te6edf3SerialPortTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3failure Tff7b72= Te6edf3runCatching Tb4b4b4{ Tff7b72if Tb4b4b4(Te6edf3portTb4b4b4.Te6edf3isOpenTb4b4b4) Te6edf3portTb4b4b4.Te6edf3closePortTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4.Te6edf3exceptionOrNullTb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3failure Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3failureTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3portNameTa5d6ff] Failed to close serial portTa5d6ff" Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72data Tff7b72class T56d364SerialReadStepTb4b4b4(Tff7b72val Te6edf3continueReadingTb4b4b4: Tffa657BooleanTb4b4b4, Tff7b72val Te6edf3failedTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4)

Tff7b72private Tff7b72fun Td2a8ffprocessSerialReadTb4b4b4(
Te6edf3readResultTb4b4b4: Te6edf3ResultTff7b72<Tffa657IntTff7b72>Tb4b4b4,
Te6edf3bufferTb4b4b4: Te6edf3ByteArrayTb4b4b4,
Te6edf3portNameTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3lifecycleTb4b4b4: Te6edf3TransportLifecycleGateTb4b4b4,
Te6edf3readCharTb4b4b4: Tb4b4b4(Tffa657ByteTb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3SerialReadStep Tb4b4b4{
Tff7b72val Te6edf3failure Tff7b72= Te6edf3readResultTb4b4b4.Te6edf3exceptionOrNullTb4b4b4(Tb4b4b4)
Tff7b72return Tff7b72when Tb4b4b4{
Te6edf3failure Tff7b72=Tff7b72= Tff7b72null Tff7b72-Tff7b72> Tb4b4b4{
Tff7b72val Te6edf3numRead Tff7b72= Te6edf3readResultTb4b4b4.Te6edf3getOrThrowTb4b4b4(Tb4b4b4)
Tff7b72when Tb4b4b4{
Te6edf3numRead Tff7b72=Tff7b72= Tff7b72-T79c0ff1 Tff7b72-Tff7b72> Te6edf3SerialReadStepTb4b4b4(Te6edf3continueReading Tff7b72= Tff7b72falseTb4b4b4, Te6edf3failed Tff7b72= Tff7b72trueTb4b4b4)

Te6edf3numRead Tff7b72<Tff7b72= T79c0ff0 Tff7b72-Tff7b72> Te6edf3SerialReadStepTb4b4b4(Te6edf3continueReading Tff7b72= Tff7b72trueTb4b4b4)

Tff7b72else Tff7b72-Tff7b72> Tb4b4b4{
Tff7b72val Te6edf3admitted Tff7b72= Te6edf3lifecycleTb4b4b4.Te6edf3runIfOpen Tb4b4b4{ Tff7b72for Tb4b4b4(Te6edf3i Tff7b72in T79c0ff0 Te6edf3until Te6edf3numReadTb4b4b4) Te6edf3readCharTb4b4b4(Te6edf3bufferTff7b72[Te6edf3iTff7b72]Tb4b4b4) Tb4b4b4}
Te6edf3SerialReadStepTb4b4b4(Te6edf3continueReading Tff7b72= Te6edf3admitted Tff7b72!Tff7b72= Tff7b72nullTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Te6edf3failure Tff7b72is Te6edf3SerialPortTimeoutException Tff7b72-Tff7b72> Te6edf3SerialReadStepTb4b4b4(Te6edf3continueReading Tff7b72= Tff7b72trueTb4b4b4)

Te6edf3failure Tff7b72is Te6edf3CancellationException Tff7b72-Tff7b72> Tff7b72throw Te6edf3failure

Te6edf3failure Tff7b72!is Te6edf3Exception Tff7b72-Tff7b72> Tff7b72throw Te6edf3failure

Tff7b72else Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3failureTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3portNameTa5d6ff] Serial read errorTa5d6ff" Tb4b4b4}
Te6edf3SerialReadStepTb4b4b4(Te6edf3continueReading Tff7b72= Tff7b72falseTb4b4b4, Te6edf3failed Tff7b72= Tff7b72trueTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffrunSerialReadLoopTb4b4b4(
Te6edf3portTb4b4b4: Te6edf3SerialPortTb4b4b4,
Te6edf3portNameTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3lifecycleTb4b4b4: Te6edf3TransportLifecycleGateTb4b4b4,
Te6edf3readCharTb4b4b4: Tb4b4b4(Tffa657ByteTb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4,
Tb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Tff7b72val Te6edf3input Tff7b72= Te6edf3portTb4b4b4.Te6edf3inputStream
Tff7b72val Te6edf3buffer Tff7b72= Te6edf3ByteArrayTb4b4b4(Te6edf3SERIAL_READ_BUFFER_SIZETb4b4b4)
Tff7b72var Te6edf3endedUnexpectedly Tff7b72= Tff7b72false
Tff7b72try Tb4b4b4{
Tff7b72var Te6edf3reading Tff7b72= Tff7b72true
Tff7b72while Tb4b4b4(Te6edf3currentCoroutineContextTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3isActive Tff7b72&Tff7b72& Te6edf3portTb4b4b4.Te6edf3isOpen Tff7b72&Tff7b72& Te6edf3readingTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3step Tff7b72= Te6edf3processSerialReadTb4b4b4(Te6edf3runCatching Tb4b4b4{ Te6edf3inputTb4b4b4.Te6edf3readTb4b4b4(Te6edf3bufferTb4b4b4) Tb4b4b4}Tb4b4b4, Te6edf3bufferTb4b4b4, Te6edf3portNameTb4b4b4, Te6edf3lifecycleTb4b4b4, Te6edf3readCharTb4b4b4)
Te6edf3reading Tff7b72= Te6edf3stepTb4b4b4.Te6edf3continueReading
Te6edf3endedUnexpectedly Tff7b72= Te6edf3endedUnexpectedly Tff7b72|Tff7b72| Te6edf3stepTb4b4b4.Te6edf3failed
Tb4b4b4}
Te6edf3endedUnexpectedly Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3currentCoroutineContextTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3isActiveTb4b4b4) Tb4b4b4{
Te6edf3endedUnexpectedly Tff7b72|Tff7b72| Tff7b72!Te6edf3lifecycleTb4b4b4.Te6edf3isClosed
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72false
Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{
Te6edf3runCatching Tb4b4b4{ Te6edf3inputTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4) Tb4b4b4}
Tb4b4b4}
Tff7b72return Te6edf3endedUnexpectedly
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffpublishSerialCallbackIfOpenTb4b4b4(
Te6edf3lifecycleTb4b4b4: Te6edf3TransportLifecycleGateTb4b4b4,
Te6edf3stateTb4b4b4: Te6edf3SerialPortStateTb4b4b4,
Te6edf3expectedPortTb4b4b4: Te6edf3SerialPort? Tff7b72= Tff7b72nullTb4b4b4,
Te6edf3requireNoPublishedPortTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4,
Te6edf3blockTb4b4b4: Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4,
Tb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Te6edf3lifecycleTb4b4b4.Te6edf3runIfOpen Tb4b4b4{
Tff7b72val Te6edf3publish Tff7b72= Te6edf3stateTb4b4b4.Te6edf3canPublishTb4b4b4(Te6edf3expectedPortTb4b4b4, Te6edf3requireNoPublishedPortTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3publishTb4b4b4) Te6edf3blockTb4b4b4(Tb4b4b4)
Te6edf3publish
Tb4b4b4} Tff7b72?: Tff7b72false

T8b949e/**
* JVM-specific implementation of [RadioTransport] using jSerialComm. Uses [StreamTransport] for START1/START2 packet
* framing.
*
* Use the [create] factory method instead of the constructor directly. Construction is side-effect free; [start] opens
* the serial port and publishes the connection.
*/
Tff7b72class T56d364SerialTransport
Te6edf3private Tff7b72constructorTb4b4b4(
Tff7b72private Tff7b72val Te6edf3portNameTb4b4b4: Tffa657StringTb4b4b4,
Tff7b72private Tff7b72val Te6edf3baudRateTb4b4b4: Tffa657Int Tff7b72= Te6edf3DEFAULT_BAUD_RATETb4b4b4,
Te6edf3callbackTb4b4b4: Te6edf3RadioTransportCallbackTb4b4b4,
Te6edf3scopeTb4b4b4: Te6edf3CoroutineScopeTb4b4b4,
Tff7b72private Tff7b72val Te6edf3dispatchersTb4b4b4: Te6edf3CoroutineDispatchersTb4b4b4,
Tb4b4b4) Tb4b4b4: Te6edf3StreamTransportTb4b4b4(Te6edf3callbackTb4b4b4, Te6edf3scopeTb4b4b4) Tb4b4b4{
Tff7b72private Tff7b72val Te6edf3lifecycle Tff7b72= Te6edf3TransportLifecycleGateTb4b4b4(Ta5d6ff"Ta5d6ffJVM serialTa5d6ff"Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3portState Tff7b72= Te6edf3SerialPortStateTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3heartbeatSender Tff7b72= Te6edf3HeartbeatSenderTb4b4b4(Te6edf3sendToRadio Tff7b72= Tb4b4b4{ Te6edf3handleSendToRadioTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}Tb4b4b4, Te6edf3logTag Tff7b72= Ta5d6ff"Ta5d6ffSerial[Tffd700$Te6edf3portNameTa5d6ff]Ta5d6ff"Tb4b4b4)

Tff7b72override Tff7b72fun Td2a8ffstartTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3job Tff7b72= Te6edf3scopeTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4, Te6edf3start Tff7b72= Te6edf3CoroutineStartTb4b4b4.Te6edf3LAZYTb4b4b4) Tb4b4b4{ Te6edf3runConnectionStartTb4b4b4(Tb4b4b4) Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3portStateTb4b4b4.Te6edf3publishStartJobTb4b4b4(Te6edf3jobTb4b4b4, Te6edf3lifecycleTb4b4b4.Te6edf3isClosedTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3jobTb4b4b4.Te6edf3startTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3jobTb4b4b4.Te6edf3cancelTb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3lifecycleTb4b4b4.Te6edf3isClosedTb4b4b4) Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3portNameTa5d6ff] Ignoring start after serial transport closeTa5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffrunConnectionStartTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3lease Tff7b72= Te6edf3lifecycleTb4b4b4.Te6edf3tryAcquireTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72return
Tff7b72try Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3startConnectionTb4b4b4(Tb4b4b4) Tff7b72&Tff7b72& Tff7b72!Te6edf3lifecycleTb4b4b4.Te6edf3isClosedTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3errorMessage Tff7b72= Te6edf3diagnoseSerialOpenFailureTb4b4b4(Te6edf3portNameTb4b4b4)
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3portNameTa5d6ff] Serial port could not be opened; signalling disconnectTa5d6ff" Tb4b4b4}
Te6edf3publishSerialCallbackIfOpenTb4b4b4(Te6edf3lifecycleTb4b4b4, Te6edf3portStateTb4b4b4, Te6edf3requireNoPublishedPort Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4{
Te6edf3callbackTb4b4b4.Te6edf3onDisconnectTb4b4b4(Te6edf3isPermanent Tff7b72= Tff7b72falseTb4b4b4, Te6edf3errorMessage Tff7b72= Te6edf3errorMessageTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{
Te6edf3leaseTb4b4b4.Te6edf3releaseTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e/** Attempts to open the serial port and starts the read loop. Returns true if successful, false otherwise. */
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffstartConnectionTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3portStateTb4b4b4.Te6edf3isClosingTb4b4b4(Te6edf3lifecycleTb4b4b4.Te6edf3isClosedTb4b4b4)Tb4b4b4) Tff7b72return Tff7b72false
Tff7b72var Te6edf3candidatePortTb4b4b4: Te6edf3SerialPort? Tff7b72= Tff7b72null
Tff7b72val Te6edf3attempt Tff7b72= Te6edf3runCatching Tb4b4b4{
Tff7b72val Te6edf3port Tff7b72= Te6edf3SerialPortTb4b4b4.Te6edf3getCommPortTb4b4b4(Te6edf3portNameTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3port Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72false
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3candidatePort Tff7b72= Te6edf3port
Te6edf3configureSerialPortTb4b4b4(Te6edf3portTb4b4b4, Te6edf3baudRateTb4b4b4)
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3runInterruptibleTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{ Te6edf3portTb4b4b4.Te6edf3openPortTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3portNameTa5d6ff] Serial port openPort() returned falseTa5d6ff" Tb4b4b4}
Te6edf3closeSerialPortTb4b4b4(Te6edf3portNameTb4b4b4, Te6edf3portTb4b4b4)
Te6edf3candidatePort Tff7b72= Tff7b72null
Tff7b72false
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3portTb4b4b4.Te6edf3setDTRTb4b4b4(Tb4b4b4)
Te6edf3portTb4b4b4.Te6edf3setRTSTb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3portStateTb4b4b4.Te6edf3publishPortTb4b4b4(Te6edf3portTb4b4b4, Te6edf3lifecycleTb4b4b4.Te6edf3isClosedTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3closeSerialPortTb4b4b4(Te6edf3portNameTb4b4b4, Te6edf3portTb4b4b4)
Te6edf3candidatePort Tff7b72= Tff7b72null
Tff7b72false
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3candidatePort Tff7b72= Tff7b72null
Te6edf3finishPublishedPortTb4b4b4(Te6edf3portTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72val Te6edf3failure Tff7b72= Te6edf3attemptTb4b4b4.Te6edf3exceptionOrNullTb4b4b4(Tb4b4b4)
Te6edf3candidatePortTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3closeSerialPortTb4b4b4(Te6edf3portNameTb4b4b4, Tffa657itTb4b4b4) Tb4b4b4}
Tff7b72return Tff7b72when Tb4b4b4{
Te6edf3failure Tff7b72=Tff7b72= Tff7b72null Tff7b72-Tff7b72> Te6edf3attemptTb4b4b4.Te6edf3getOrDefaultTb4b4b4(Tff7b72falseTb4b4b4)

Te6edf3failure Tff7b72is Te6edf3CancellationException Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3portStateTb4b4b4.Te6edf3takePortTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3closeSerialPortTb4b4b4(Te6edf3portNameTb4b4b4, Tffa657itTb4b4b4) Tb4b4b4}
Tff7b72throw Te6edf3failure
Tb4b4b4}

Te6edf3failure Tff7b72!is Te6edf3Exception Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3portStateTb4b4b4.Te6edf3takePortTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3closeSerialPortTb4b4b4(Te6edf3portNameTb4b4b4, Tffa657itTb4b4b4) Tb4b4b4}
Tff7b72throw Te6edf3failure
Tb4b4b4}

Tff7b72else Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3portStateTb4b4b4.Te6edf3takePortTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3closeSerialPortTb4b4b4(Te6edf3portNameTb4b4b4, Tffa657itTb4b4b4) Tb4b4b4}
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3failureTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3portNameTa5d6ff] Serial connection failedTa5d6ff" Tb4b4b4}
Tff7b72false
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72suspend Tff7b72fun Td2a8fffinishPublishedPortTb4b4b4(Te6edf3portTb4b4b4: Te6edf3SerialPortTb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3portNameTa5d6ff] Serial port opened (baud=Tffd700$Te6edf3baudRateTa5d6ff)Ta5d6ff" Tb4b4b4}
Te6edf3runInterruptibleTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{
Te6edf3writeFullyWithDeadlineTb4b4b4(Te6edf3portTb4b4b4, Te6edf3StreamFrameCodecTb4b4b4.Te6edf3WAKE_BYTESTb4b4b4, Te6edf3portNameTb4b4b4, Te6edf3SERIAL_WRITE_TIMEOUT_MSTb4b4b4)
Tb4b4b4}
Tff7b72val Te6edf3connected Tff7b72= Te6edf3publishSerialCallbackIfOpenTb4b4b4(Te6edf3lifecycleTb4b4b4, Te6edf3portStateTb4b4b4, Te6edf3expectedPort Tff7b72= Te6edf3portTb4b4b4) Tb4b4b4{ Te6edf3callbackTb4b4b4.Te6edf3onConnectTb4b4b4(Tb4b4b4) Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3connectedTb4b4b4) Te6edf3startReadLoopTb4b4b4(Te6edf3portTb4b4b4)
Tff7b72return Te6edf3connected
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffstartReadLoopTb4b4b4(Te6edf3portTb4b4b4: Te6edf3SerialPortTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3job Tff7b72=
Te6edf3scopeTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4, Te6edf3start Tff7b72= Te6edf3CoroutineStartTb4b4b4.Te6edf3LAZYTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3endedUnexpectedly Tff7b72= Te6edf3runSerialReadLoopTb4b4b4(Te6edf3portTb4b4b4, Te6edf3portNameTb4b4b4, Te6edf3lifecycleTb4b4b4, Tff7b72::Te6edf3readCharTb4b4b4)
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3portNameTa5d6ff] Serial read loop exitingTa5d6ff" Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3portStateTb4b4b4.Te6edf3retirePortTb4b4b4(Te6edf3portTb4b4b4)Tb4b4b4) Te6edf3closeSerialPortTb4b4b4(Te6edf3portNameTb4b4b4, Te6edf3portTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3endedUnexpectedlyTb4b4b4) Tb4b4b4{
Te6edf3publishSerialCallbackIfOpenTb4b4b4(Te6edf3lifecycleTb4b4b4, Te6edf3portStateTb4b4b4, Te6edf3requireNoPublishedPort Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4{
Te6edf3onDeviceDisconnectTb4b4b4(Te6edf3waitForStopped Tff7b72= Tff7b72trueTb4b4b4, Te6edf3isPermanent Tff7b72= Tff7b72falseTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3portStateTb4b4b4.Te6edf3publishReadJobTb4b4b4(Te6edf3portTb4b4b4, Te6edf3jobTb4b4b4, Te6edf3lifecycleTb4b4b4.Te6edf3isClosedTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3portNameTa5d6ff] Starting serial read loopTa5d6ff" Tb4b4b4}
Te6edf3jobTb4b4b4.Te6edf3startTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3jobTb4b4b4.Te6edf3cancelTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72fun Td2a8ffhandleSendToRadioTb4b4b4(Te6edf3pTb4b4b4: Te6edf3ByteArrayTb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Tff7b72val Te6edf3lease Tff7b72= Te6edf3lifecycleTb4b4b4.Te6edf3tryAcquireTb4b4b4(Tb4b4b4) Tff7b72?: Tff7b72return Tff7b72false
Tff7b72val Te6edf3port Tff7b72= Te6edf3portStateTb4b4b4.Te6edf3currentOpenPortTb4b4b4(Tb4b4b4)
Tff7b72return Tff7b72if Tb4b4b4(Te6edf3port Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3leaseTb4b4b4.Te6edf3releaseTb4b4b4(Tb4b4b4)
Tff7b72false
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3queueFramedSendTb4b4b4(
Te6edf3payload Tff7b72= Te6edf3pTb4b4b4,
Te6edf3writer Tff7b72= Tb4b4b4{ Te6edf3bytes Tff7b72-Tff7b72>
Te6edf3runInterruptibleTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{
Te6edf3writeFullyWithDeadlineTb4b4b4(Te6edf3portTb4b4b4, Te6edf3bytesTb4b4b4, Te6edf3portNameTb4b4b4, Te6edf3SERIAL_WRITE_TIMEOUT_MSTb4b4b4)
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Te6edf3flusher Tff7b72= Tb4b4b4{Tb4b4b4}Tb4b4b4,
Te6edf3onCompletion Tff7b72= Te6edf3leaseTff7b72::Te6edf3releaseTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72fun Td2a8ffsendBytesTb4b4b4(Te6edf3pTb4b4b4: Te6edf3ByteArrayTb4b4b4) Tb4b4b4{
Te6edf3portStateTb4b4b4.Te6edf3currentOpenPortTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3port Tff7b72-Tff7b72> Te6edf3writeFullyWithDeadlineTb4b4b4(Te6edf3portTb4b4b4, Te6edf3pTb4b4b4, Te6edf3portNameTb4b4b4, Te6edf3SERIAL_WRITE_TIMEOUT_MSTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72fun Td2a8ffflushBytesTb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// Raw SerialPort.writeBytes writes directly to the driver buffer; there is no user-space stream to flush.
Tb4b4b4}

Tff7b72override Tff7b72fun Td2a8ffkeepAliveTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3scopeTb4b4b4.Te6edf3handledLaunch Tb4b4b4{ Te6edf3heartbeatSenderTb4b4b4.Te6edf3sendHeartbeatTb4b4b4(Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffcloseTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3withContextTb4b4b4(Te6edf3NonCancellableTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3portNameTa5d6ff] Closing serial transportTa5d6ff" Tb4b4b4}
Tff7b72val Te6edf3currentStartJob Tff7b72= Te6edf3portStateTb4b4b4.Te6edf3beginCloseTb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3currentStartJob Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3currentStartJobTb4b4b4.Te6edf3cancelTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3joined Tff7b72= Te6edf3withTimeoutOrNullTb4b4b4(Te6edf3SERIAL_START_JOIN_TIMEOUTTb4b4b4) Tb4b4b4{ Te6edf3currentStartJobTb4b4b4.Te6edf3joinTb4b4b4(Tb4b4b4) Tb4b4b4} Tff7b72!Tff7b72= Tff7b72null
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3joinedTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3portNameTa5d6ff] Serial open did not stop within Tffd700$Te6edf3SERIAL_START_JOIN_TIMEOUTTa5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
T8b949e// beginClose makes new sends reject synchronously. Stop the framed-send worker now so queued sends release
T8b949e// their lifecycle leases before the gate waits for admitted operations.
Tff7b72superTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3completed Tff7b72=
Te6edf3lifecycleTb4b4b4.Te6edf3close Tb4b4b4{
Tff7b72val Te6edf3currentReadJob Tff7b72= Te6edf3portStateTb4b4b4.Te6edf3takeReadJobTb4b4b4(Tb4b4b4)
Te6edf3runInterruptibleTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{ Te6edf3portStateTb4b4b4.Te6edf3takePortTb4b4b4(Tb4b4b4)Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3closeSerialPortTb4b4b4(Te6edf3portNameTb4b4b4, Tffa657itTb4b4b4) Tb4b4b4} Tb4b4b4}
Te6edf3currentReadJobTff7b72?.Te6edf3cancelAndJoinTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3completedTb4b4b4) Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ff[Tffd700$Te6edf3portNameTa5d6ff] JVM serial teardown did not complete within its lifecycle boundsTa5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72companion Tff7b72object Tb4b4b4{
Tff7b72private Tff7b72const Tff7b72val Te6edf3DEFAULT_BAUD_RATE Tff7b72= T79c0ff1T79c0ff1T79c0ff5T79c0ff2T79c0ff0T79c0ff0

T8b949e/**
* Creates a side-effect-free [SerialTransport]. The owning transport service invokes [SerialTransport.start]
* after it has published session ownership, so even immediate serial callbacks carry the correct generation.
*/
Tff7b72fun Td2a8ffcreateTb4b4b4(
Te6edf3portNameTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3baudRateTb4b4b4: Tffa657Int Tff7b72= Te6edf3DEFAULT_BAUD_RATETb4b4b4,
Te6edf3callbackTb4b4b4: Te6edf3RadioTransportCallbackTb4b4b4,
Te6edf3scopeTb4b4b4: Te6edf3CoroutineScopeTb4b4b4,
Te6edf3dispatchersTb4b4b4: Te6edf3CoroutineDispatchersTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3SerialTransport Tff7b72= Te6edf3SerialTransportTb4b4b4(Te6edf3portNameTb4b4b4, Te6edf3baudRateTb4b4b4, Te6edf3callbackTb4b4b4, Te6edf3scopeTb4b4b4, Te6edf3dispatchersTb4b4b4)

T8b949e/** Returns names of all available serial ports. */
Tff7b72fun Td2a8ffgetAvailablePortsTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3ListTff7b72<Tffa657StringTff7b72> Tff7b72= Te6edf3SerialPortTb4b4b4.Te6edf3getCommPortsTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3systemPortName Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.15s